package com.insurance.modules.claim.controller;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.insurance.common.annotation.SysLog;
import com.insurance.common.common.ResponseData;
import com.insurance.common.enums.CommonEnum;
import com.insurance.common.utils.AmountUtils;
import com.insurance.common.utils.QueryList;
import com.insurance.common.utils.R;
import com.insurance.modules.claim.constants.AttachmentEnum;
import com.insurance.modules.claim.constants.EntityTypeEnum;
import com.insurance.modules.claim.entity.*;
import com.insurance.modules.claim.service.*;
import com.insurance.modules.claim.vo.convert.ClaimCaseExcelConvert;
import com.insurance.modules.claim.vo.request.*;
import com.insurance.modules.claim.vo.response.CaseListExportRsp;
import com.insurance.modules.claim.vo.response.*;
import com.insurance.modules.sys.controller.AbstractController;
import com.insurance.modules.sys.service.SysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 案件表
 *
 * @author weiruifeng
 * @email
 * @date 2021-09-24 17:42:47
 */

@Slf4j
@Api(tags = "案件")
@RestController
@RequestMapping("claim/claimcase")
public class ClaimCaseController extends AbstractController {
    @Autowired
    private ClaimCaseService claimCaseService;
    @Autowired
    private InsuredInfoService insuredInfoService;
    @Autowired
    private PolicyInfoService policyInfoService;
    @Autowired
    private ClaimSettlementService claimSettlementService;
    @Autowired
    private FileInfoService fileInfoService;
    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private CaseImporTaskService caseImporTaskService;

    private @Value("${upload.preview.path}") String previewPath;
    private @Value("${upload.preview.url}") String previewUrl;

    /**
     * 分页列表
     */
    @PostMapping("/pageList")
    @RequiresPermissions("claim:claimcase:pageList")
    @ApiOperation(value = "查询分页列表", notes = "根据条件查询分页列表")
    public ResponseData<Page<CaseListRsp>> pageList(@RequestBody QueryList<CaseListReq> param) {
        Long userId = getUserId();
        if (Objects.isNull(userId)) {
            return ResponseData.error(CommonEnum.USER_TOKEN_ERROR);
        }
        CaseListReq req = param.getParams();
        if(null != req.getCaseStatus() && req.getCaseStatus() == 3){
            //查询已结案的，按结案时间（打款时间）倒叙
            req.setOrderBy(" a.pay_time desc ");
        }
        req.setAcceptorId(userId);
        req.setAuthDeptIds(sysUserService.getById(userId).getAuthDeptIds());
        Page<CaseListRsp> page = new Page<>(param.getPage(), param.getPageSize());
        page = claimCaseService.pageList(page, req);
        return ResponseData.success(page);
    }

    /**
     * 保存
     */
    @PostMapping("/save")
    @RequiresPermissions("claim:claimcase:save")
    @ApiOperation(value = "保存案件等信息", notes = "保存案件等信息")
    @Transactional
    public R save(@RequestBody CaseInfoSaveReq req) {
        logger.info("保存案件等信息 save==>{}", JSON.toJSONString(req));
        Long userid = getUserId();
        String username = getUserName();
        //取最新的订单号
        String maxCaseNo = claimCaseService.getMaxCaseNo();
        req.getClaimCase().setCaseNo(maxCaseNo);

        // 1.保存出险人信息
        InsuredInfoEntity insuredInfo = req.getInsuredInfo();
        insuredInfoService.save(insuredInfo);
        // 2.保存保单快照
        PolicyInfoReq policyInfo = req.getPolicyInfo();
        policyInfo.setInsuredAmount(AmountUtils.yuanToFenLong(policyInfo.getInsuredAmountYuan()));
        policyInfoService.save(policyInfo);
        // 3.保存案件信息
        ClaimCaseReq claimCase = req.getClaimCase();
        claimCase.setEstimatedLoss(AmountUtils.yuanToFenLong(claimCase.getEstimatedLossYuan()));
        claimCase.setInsuredId(insuredInfo.getId());
        claimCase.setInsuredName(insuredInfo.getInsuredName());
        claimCase.setPolicyId(policyInfo.getId());
        claimCase.setPolicyNo(policyInfo.getPolicyNo());
        claimCase.setFirstAcceptorId(userid);
        claimCase.setFirstAcceptorName(username);
        Date date = new Date();
        claimCase.setCreateTime(date);
        claimCase.setCreateBy(userid);
        claimCase.setUpdateBy(userid);
        claimCase.setUpdateTime(date);
        claimCase.setDeptId(getUser().getDeptId());
        claimCaseService.save(claimCase);
        String caseId = claimCase.getId();
        // 4.保存案件理赔记录信息
        ClaimSettlementEntity claimSettlement = new ClaimSettlementEntity();
        claimSettlement.setCaseId(caseId);
        claimSettlement.setAcceptorId(userid);
        claimSettlement.setAcceptorName(username);
        claimSettlement.setCreateBy(userid);
        claimSettlement.setCreateTime(date);
        claimSettlement.setUpdateBy(userid);
        claimSettlement.setUpdateTime(date);
        claimSettlementService.save(claimSettlement);
        //保存事故现场照片
        List<FileInfoEntity> files = req.getFiles();
        if(CollectionUtils.isNotEmpty(files)){
            for (FileInfoEntity file : files) {
                file.setBusinessId(caseId);
                file.setCreateTime(date);
                file.setCreateBy(userid);
            }
            //批量保存
            fileInfoService.saveBatch(files);
        }
        return R.ok();
    }

    /**
     * 修改案件信息
     */
/*    @PostMapping("/update")
    @RequiresPermissions("claim:claimcase:update")
    @ApiOperation(value = "修改案件信息", notes = "修改案件信息")
    public R update(@RequestBody ClaimCaseEntity claimCase) {
        claimCaseService.updateById(claimCase);
        return R.ok();
    }*/

    /**
     * 保存
     */
    @PostMapping("/update")
    //@RequiresPermissions("claim:claimcase:update")
    @ApiOperation(value = "修改案件等信息", notes = "修改案件等信息")
    @Transactional
    public R update(@RequestBody CaseInfoSaveReq req) {
        logger.info("修改案件等信息 CaseInfoSaveReq:{}", JSON.toJSONString(req));
        Long userid = getUserId();
        // 1.保存出险人信息
        InsuredInfoEntity insuredInfo = req.getInsuredInfo();
        insuredInfoService.updateById(insuredInfo);
        // 2.保存保单快照
        PolicyInfoReq policyInfo = req.getPolicyInfo();
        policyInfo.setInsuredAmount(AmountUtils.yuanToFenLong(policyInfo.getInsuredAmountYuan()));
        policyInfoService.updateById(policyInfo);
        // 3.保存案件信息
        ClaimCaseReq claimCase = req.getClaimCase();
        claimCase.setEstimatedLoss(AmountUtils.yuanToFenLong(claimCase.getEstimatedLossYuan()));
        claimCase.setInsuredName(insuredInfo.getInsuredName());
        claimCase.setPolicyNo(policyInfo.getPolicyNo());
        Date date = new Date();
        claimCase.setUpdateBy(userid);
        claimCase.setUpdateTime(date);
        claimCaseService.updateById(claimCase);

        List<FileInfoEntity> files = req.getFiles();
        if(CollectionUtils.isNotEmpty(files)){
            files = files.stream().filter(x -> x.getBusinessId().equals(claimCase.getId())).peek(x -> {
                x.setCreateTime(date);
                x.setCreateBy(userid);
            }).collect(Collectors.toList());
            //批量保存
            if(CollectionUtils.isNotEmpty(files)){
                logger.info("修改案件等信息 files===>{}", JSON.toJSONString(files));
                fileInfoService.saveBatch(files);
            }
        }
        List<String> deleteFiles = req.getDeleteFiles();
        if(CollectionUtils.isNotEmpty(deleteFiles)){
            //根据id批量删除
            fileInfoService.removeByIds(deleteFiles);
        }
        return R.ok();
    }

    /**
     * 根据理赔记录查询案件详细信息
     */
    @PostMapping("/query/{settlementId}")
    //@RequiresPermissions("claim:claimcase:query")
    @ApiOperation(value = "查询案件详细信息", notes = "查询案件详细信息")
    public ResponseData<JSONObject> queryDetailById(@PathVariable("settlementId") String settlementId) {
        logger.info("根据理赔记录查询案件详细信息 settlementId:{}", settlementId);
        //获取对应的理赔记录
        ClaimSettlementEntity settlementEntity = claimSettlementService.getById(settlementId);
        if(null == settlementEntity){
            return ResponseData.error(CommonEnum.QUERY_ERROR_NODATA);
        }
        //获取案件id
        JSONObject jsonObject = new JSONObject();
        ClaimCaseEntity claimCaseEntity = claimCaseService.getById(settlementEntity.getCaseId());
        ClaimCaseReq claimCaseReq = new ClaimCaseReq();
        BeanUtils.copyProperties(claimCaseEntity, claimCaseReq);
        claimCaseReq.setEstimatedLossYuan(AmountUtils.fenToYuanBigDecimal(claimCaseReq.getEstimatedLoss()));
        jsonObject.put("claimCase", claimCaseReq);
        PolicyInfoEntity policyInfo = policyInfoService.getById(claimCaseEntity.getPolicyId());
        PolicyInfoReq policyInfoReq = new PolicyInfoReq();
        BeanUtils.copyProperties(policyInfo, policyInfoReq);
        policyInfoReq.setInsuredAmountYuan(AmountUtils.fenToYuanBigDecimal(policyInfo.getInsuredAmount()));
        jsonObject.put("policyInfo", policyInfoReq);
        InsuredInfoEntity insuredInfo = insuredInfoService.getById(claimCaseEntity.getInsuredId());
        jsonObject.put("insuredInfo", insuredInfo);
        //查询事故照片
        List<FileInfoEntity> files = fileInfoService.listByBusinessIdAndAttachment(claimCaseEntity.getId(), AttachmentEnum.accidentPicUrl, EntityTypeEnum.claimCase);
        jsonObject.put("files", files);

        logger.info("根据理赔记录查询案件详细信息 settlementId:{}, 返回信息==>{} ", settlementId, JSON.toJSONString(jsonObject));
        return ResponseData.success(jsonObject);
    }

    /**
     * 生成案件编号
     */
    @PostMapping("/makeCaseNo")
    //@RequiresPermissions("claim:claimcase:query")
    @ApiOperation(value = "生成案件编号", notes = "生成案件编号")
    public ResponseData<String> makeCaseNo() {
        String caseNo = claimCaseService.getMaxCaseNo();
        return ResponseData.success(caseNo);
    }


    @GetMapping("/export")
    //@RequiresPermissions("claim:claimcase:export")
    @ApiOperation(value = "导出", notes = "导出")
    public void export(ClaimCaseExportRequestParam req, HttpServletResponse response) throws IOException {
        Long userId = getUserId();
        if (Objects.isNull(userId)) {
            return;
        }
        try {
            req.setAcceptorId(userId);
            req.setAuthDeptIds(sysUserService.getById(userId).getAuthDeptIds());

            List<CaseListExportRsp> records = claimCaseService.pageExportList(req);

            List<CaseListExcelExport> listExcelList = ClaimCaseExcelConvert.INSTANCE.convert(records);

            ExcelWriter writer = ExcelUtil.getWriter(true);

            final int columnCount = 40;//总共40列
//            writer.merge(columnCount-1, "雇主险理赔系统报表");
            //writer.getSheet().setDefaultColumnWidth(10);
            for (int i = 0; i < columnCount; i++) {
                writer.getSheet().setColumnWidth(i, 20*256);
            }
            //自定义标题别名
            //t_claim_case
            writer.addHeaderAlias("caseNo", "案件编号");
            writer.addHeaderAlias("reportTime", "记录时间");//
            writer.addHeaderAlias("region", "区域");//
            writer.addHeaderAlias("corpName", "集团名称");
            writer.addHeaderAlias("insuredName", "被保险人");
            writer.addHeaderAlias("underwriteCorp", "承保公司");
            writer.addHeaderAlias("policyNo", "保单号");
            writer.addHeaderAlias("startTime", "保险期间");
            writer.addHeaderAlias("iInsuredName", "出险人");
            writer.addHeaderAlias("certificateNo", "身份证");
            writer.addHeaderAlias("phone", "出险人联系方式");
            writer.addHeaderAlias("accidentTime", "出险时间");
            writer.addHeaderAlias("personnelSort", "人员类别");
            writer.addHeaderAlias("outsourcingFlag", "是否外包");
            writer.addHeaderAlias("insuredAmount", "保额");
            writer.addHeaderAlias("treatAgainFlag", "是否涉及二次医疗");//
            writer.addHeaderAlias("accidentDescription", "出险描述");
            writer.addHeaderAlias("reporterName", "报案人");//t_claim_case
            writer.addHeaderAlias("reporterPhone", "报案人联系方式");
            writer.addHeaderAlias("accidentType", "事故类型");
            writer.addHeaderAlias("accidentNature", "事故性质");
            writer.addHeaderAlias("accidentLiability", "事故责任");//
            writer.addHeaderAlias("familyWantAmount", "死亡家属实际索要金额");//
            writer.addHeaderAlias("sendTime", "向保险公司报案时间");
            writer.addHeaderAlias("getFileTime", "收到理赔原件时间");//
            writer.addHeaderAlias("sendCorpTime", "理赔材料递交保险公司日期");//
            writer.addHeaderAlias("caseStatus", "案件状态");
            writer.addHeaderAlias("treatmentType", "就诊类型");//
            writer.addHeaderAlias("invoiceAmount", "发票金额");//
            writer.addHeaderAlias("treatmentAmount", "医疗费用赔付");//
            writer.addHeaderAlias("delayWorkAmount", "误工费赔付");//
            writer.addHeaderAlias("deathAmount", "身故赔付");//
            writer.addHeaderAlias("disabilityAmount", "残疾赔付");//
            writer.addHeaderAlias("disabilityAppraisalAmount", "伤残鉴定费");//
            writer.addHeaderAlias("disabilityAppraisalLevel", "伤残鉴定级别");
            writer.addHeaderAlias("publicAmount", "公共保额赔付");//
            writer.addHeaderAlias("employerAmount", "雇主法律责任条款赔付");//
            writer.addHeaderAlias("totalAmount", "赔付总金额");
            writer.addHeaderAlias("closeTime", "结案日期");
            writer.addHeaderAlias("firstAcceptorName", "理赔专员姓名");


//            writer.addHeaderAlias("projectId", "项目编号");
//            writer.addHeaderAlias("projectName", "项目名称");
//            writer.addHeaderAlias("insuranceStatus", "保障状态");
//            writer.addHeaderAlias("policyholderName", "投保人");
//            writer.addHeaderAlias("", "是否欠费");
//            writer.addHeaderAlias("reportTime", "报案时间");
//            writer.addHeaderAlias("accidentAddress", "事故发生地");
//            writer.addHeaderAlias("", "估损金额");
//            writer.addHeaderAlias("applyAmount", "申请赔付金额");
//            writer.addHeaderAlias("selfAmount", "自费金额");

            writer.setOnlyAlias(true);
            writer.write(listExcelList, true);

            String fileName = "理赔报表%s.xlsx";
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
            fileName = String.format(fileName, LocalDateTime.now().format(formatter));
            response.setHeader("Content-Disposition", "attachment;filename="+ URLEncoder.encode(fileName, "UTF-8"));
            response.setContentType("application/vnd.ms-excel");
            ServletOutputStream out = response.getOutputStream();
            writer.flush(out);
            writer.close();
            IoUtil.close(out);
        }catch (Exception e){
            log.error("export error：", e);
        }
    }

    @PostMapping("/importExcel")
    //@RequiresPermissions("claim:claimcase:export")
    @ApiOperation(value = "导入", notes = "导入")
    public ResponseData importExcel(MultipartFile file){
        if (file == null){
            return ResponseData.error(CommonEnum.QUERY_ERROR_NODATA);
        }
        String code = IdUtil.fastSimpleUUID();
        CaseImporTaskEntity entity = new CaseImporTaskEntity();
        entity.setCreateBy(getUserId().longValue());
        entity.setCreateTime(new Date());
        entity.setCode(code);
        entity.setName(file.getOriginalFilename());
        caseImporTaskService.save(entity);
        //异步调用
        new Thread(()->{
                try (ExcelReader excelReader = EasyExcel.read(file.getInputStream(), CaseListExcelImport.class, new CaseExcelImportListener(claimCaseService, code)).build()) {
                    // 构建一个sheet 这里可以指定名字或者no
                    ReadSheet readSheet = EasyExcel.readSheet(0).build();
                    // 读取一个sheet
                    excelReader.read(readSheet);
                    excelReader.finish();
                } catch (IOException e) {
                    CaseImporTaskEntity task = caseImporTaskService.queryByCode(code);
                    if(null != task){
                        task.setStatus(2);
                        task.setMsg("导入IO异常：" + e.getMessage());
                        task.setUpdateTime(new Date());
                        caseImporTaskService.saveOrUpdate(task);
                    }
                }
        }).start();
        return ResponseData.success(entity.getCode());

    }

    @GetMapping("/queryTaskStatus")
    //@RequiresPermissions("claim:claimcase:export")
    @ApiOperation(value = "查询导入结果", notes = "查询导入结果")
    public ResponseData importExcel(String taskCode){
        if(StringUtils.isBlank(taskCode)){
            return ResponseData.error(-1, "参数错误");
        }
        CaseImporTaskEntity task = caseImporTaskService.queryByCode(taskCode);
        if(null == task){
            return ResponseData.error(-1, "任务不存在");
        }
        return ResponseData.success(task);
    }

    /**
     * 删除用户
     */
    @SysLog("删除理赔")
    @DeleteMapping("/delete/{id}")
    @RequiresPermissions("claim:claimcase:delete")
    public R delete(@PathVariable("id") String id){
        claimCaseService.deleteById(id, getUserId());
        return R.ok();
    }

}

